package templateExecel2.extract;

import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import templateExecel2.fram.Data;
import templateExecel2.utils.PoiUtils;

import java.io.File;
import java.io.IOException;
import java.util.*;

//提取器
public class Extractor {

    public static Map<String, Object> extract(XSSFSheet template, XSSFSheet data, Map<String, Class<?>> entityMapping) {
        return extract(template, data, 1, entityMapping);
    }

    public static Map<String, Object> extract(XSSFSheet template, XSSFSheet data, int colModel, Map<String, Class<?>> entityMapping) {

        DoubleActingIndex doubleActingIndex = new DoubleActingIndex();

        Map<String, List<ValueHolder>> colValueMap = new HashMap<>();

        TemplateSheetHolder templateSheetHolder = new TemplateSheetHolder(template, colValueMap, colModel);
        DataSheetHolder dataSheetHolder = new DataSheetHolder(data, templateSheetHolder);
        doubleActingIndex.setLeft(templateSheetHolder);
        doubleActingIndex.setRight(dataSheetHolder);

        while (doubleActingIndex.next()) {

        }

        ValueHandler.setEntityMapping(entityMapping);
        return ValueHandler.handle(colValueMap);
    }


    /*
        使用extractSheet快速构建一个模板sheet页
     */
    public static Map<String, Object> extract(ExtractSheet extractSheet, XSSFSheet data, Map<String, Class<?>> entityMapping) {

        XSSFWorkbook sheets = new XSSFWorkbook();


        //创建一个模板页
        XSSFSheet template = sheets.createSheet("template");

        for (int i = 0; i < extractSheet.rows.size(); i++) {
            XSSFRow row = template.createRow(i);
            ExtractSheet.Row theRow = extractSheet.rows.get(i);
            for (Integer c : theRow.cellMap.keySet()) {
                XSSFCell cell = row.createCell(c);
                ExtractSheet.Row.Cell cell1 = theRow.cellMap.get(c);

                if (cell1.row * cell1.col > 1) {

                    //添加单元格合并
                    template.addMergedRegion(new CellRangeAddress(i, i + cell1.row - 1, c, c + cell1.col - 1));
                }

                Object v = cell1.v;

                if (v == null) {
                    continue;
                }

                if (v instanceof String) {
                    cell.setCellValue((String) v);
                } else if (v instanceof Double) {
                    cell.setCellValue((Double) v);
                } else if (v instanceof Boolean) {
                    cell.setCellValue((Boolean) v);
                } else if (v instanceof Date) {
                    cell.setCellValue((Date) v);
                } else if (v instanceof Calendar) {
                    cell.setCellValue((Calendar) v);
                } else {
                    cell.setCellValue(v.toString());
                }
            }

        }
        return extract(template, data, extractSheet.mode, entityMapping);
    }


    private static Map<Integer, Map<Integer, Merge>> handleMerge(List<CellRangeAddress> cellRangeAddresses) {
        Map<Integer, Map<Integer, Merge>> map = new HashMap<>();
        if (cellRangeAddresses.size() > 0) {
            for (CellRangeAddress cellRangeAddress : cellRangeAddresses) {
                Map<Integer, Merge> absent = map.computeIfAbsent(cellRangeAddress.getFirstRow(), k -> new HashMap<>());
                absent.computeIfAbsent(cellRangeAddress.getFirstColumn(), k -> Merge.get(cellRangeAddress.getLastRow() - cellRangeAddress.getFirstRow() + 1, cellRangeAddress.getLastColumn() - cellRangeAddress.getFirstColumn() + 1));
            }
        }
        return map;
    }

    private static class TemplateSheetHolder implements DoubleActingIndex.Handle {

        XSSFSheet template;

        //当前指针
        int current;

        //指针最大
        int max;

        Map<Integer, Map<Integer, Merge>> margeMap;

        Map<String, List<ValueHolder>> colValueMap;

        private int colModel;

        public TemplateSheetHolder(XSSFSheet template, Map<String, List<ValueHolder>> colValueMap, int colModel) {
            this.colModel = colModel;
            this.colValueMap = colValueMap;
            this.template = template;
            this.current = template.getFirstRowNum();
            this.max = template.getLastRowNum();
            this.margeMap = handleMerge(template.getMergedRegions());

            //初始化的时候跳转一次
            next();
        }

        TemplateRow templateRow;

        Map<Integer, Merge> empty = Collections.emptyMap();

        Map<Integer, Merge> getMerge(int row) {
            Map<Integer, Merge> mergeMap = margeMap.get(row);
            if (mergeMap == null) {
                mergeMap = empty;
            }
            return mergeMap;
        }

        @Override
        public boolean next() {
            while (true) {

                if (current > max) {
                    return false;
                }
                templateRow = TemplateRow.compile(template.getRow(current), getMerge(current), colValueMap, colModel);

                current++;
                if (templateRow != null) {//空白行不能作为模板行,没有任何意义
                    return true;
                }

            }
        }

        @Override
        public boolean shouldChange() {//总是跳转到另一行中
            return true;
        }

        @Override
        public void afterChange() {

        }

        @Override
        public void afterChangeTo() {

        }

        TemplateRow getTemplateRow() {
            return templateRow;
        }
    }


    private static class DataSheetHolder implements DoubleActingIndex.Handle {

        XSSFSheet data;

        //当前指针
        int current;

        //指针最大
        int max;

        Map<Integer, Map<Integer, Merge>> margeMap;

        XSSFRow row;

        Map<Integer, Merge> empty = Collections.emptyMap();

        Map<Integer, Merge> getMerge(int row) {
            Map<Integer, Merge> mergeMap = margeMap.get(row);
            if (mergeMap == null) {
                mergeMap = empty;
            }
            return mergeMap;
        }

        //可用于获取模板行数据
        TemplateSheetHolder templateSheetHolder;

        public DataSheetHolder(XSSFSheet data, TemplateSheetHolder templateSheetHolder) {
            this.templateSheetHolder = templateSheetHolder;
            this.data = data;
            this.current = data.getFirstRowNum();
            this.max = data.getLastRowNum();
            margeMap = handleMerge(data.getMergedRegions());
        }

        @Override
        public boolean next() {
            while (true) {
                if (current > max) {
                    return false;
                }
                row = data.getRow(current);
                merge = getMerge(current);
                current++;
                if (row != null) {
                    return true;
                }
            }
        }

        Map<Integer, Merge> merge;

        @Override
        public boolean shouldChange() {

            //TODO 处理跳转逻辑
            TemplateRow templateRow = templateSheetHolder.getTemplateRow();


            boolean b = templateRow.extract(row, merge);

            //表明当前行已经不符合模板行
            if (!b) {

                //指针后移一下,在变更模板行后重新判断当前行中的数据是否符合模板行
                current--;

                //改变模板行
                return true;

            }

            return false;
        }

        @Override
        public void afterChange() {
        }

        @Override
        public void afterChangeTo() {

        }
    }


    public static void main(String[] args) throws IOException {

        File d = new File("C:\\Users\\dinglei\\Desktop\\提取测试\\数据.xlsx");
        XSSFSheet ds = PoiUtils.read(d).getSheet("d");


        ExtractSheet sheet = new ExtractSheet()
                .newRow()
                .cell("A", "${list[i].name}")
                .cell("B", "${list[i].vs[j]}")
                .sheet().colIntersection();

        Map<String, Class<?>> mapping = new HashMap<>();

        mapping.put("list[i]", A.class);
        mapping.put("list[i].name", String.class);
        mapping.put("list[i].vs[j]", Integer.class);

        //使用实体映射进行处理
        Map<String, Object> extract = extract(sheet, ds, mapping);

        List<A> list= (List<A>) extract.get("list");

        for (A a : list) {
            System.out.println(a.name + "   " + a.vs);
        }

    }

    public static class A {
        private String name;
        private List<Integer> vs;
        public void setVs(List<Integer> vs) {
            this.vs = vs;
        }
        public void setName(String name) {
            this.name = name;
        }
    }


}
